// Copyright (C) 2023 即时通讯网(52im.net) & Jack Jiang.
// The RainbowChat Project. All rights reserved.
// 
// 【本产品为著作权产品，合法授权后请放心使用，禁止外传！】
// 【本次授权给：<北京小羊驼科技有限公司>，授权编号：<NT231212144350>，代码指纹：<A.702363430.550>，技术对接人微信：<ID: wxid_wbyootvkdcgj22>】
// 【授权寄送：<收件：苏先生、地址：北京市大兴区北京密码西区6号楼1单元301、电话：18613885610、邮箱：bd@huiyuanxiang-inc.com>】
// 
// 【本系列产品在国家版权局的著作权登记信息如下】：
// 1）国家版权局登记名(简称)和权证号：RainbowChat    （证书号：软著登字第1220494号、登记号：2016SR041877）
// 2）国家版权局登记名(简称)和权证号：RainbowChat-Web（证书号：软著登字第3743440号、登记号：2019SR0322683）
// 3）国家版权局登记名(简称)和权证号：RainbowAV      （证书号：软著登字第2262004号、登记号：2017SR676720）
// 4）国家版权局登记名(简称)和权证号：MobileIMSDK-Web（证书号：软著登字第2262073号、登记号：2017SR676789）
// 5）国家版权局登记名(简称)和权证号：MobileIMSDK    （证书号：软著登字第1220581号、登记号：2016SR041964）
// * 著作权所有人：江顺/苏州网际时代信息科技有限公司
// 
// 【违法或违规使用投诉和举报方式】：
// 联系邮件：jack.jiang@52im.net
// 联系微信：hellojackjiang
// 联系QQ号：413980957
// 授权说明：http://www.52im.net/thread-1115-1-1.html
// 官方社区：http://www.52im.net
package com.x52im.rainbowchat.im;

import com.eva.framework.utils.EndsExceptionFactory;
import com.eva.framework.utils.LoggerFactory;
import com.x52im.rainbowchat.BaseConf;
import com.x52im.rainbowchat.RequestWhitelist;
import com.x52im.rainbowchat.common.dto.cnst.UserProtocalsType;
import com.x52im.rainbowchat.im.dto.CMDBody4AddFriendRequest;
import com.x52im.rainbowchat.im.dto.CMDBody4ProcessFriendRequest;
import com.x52im.rainbowchat.im.impl.ChatLogicManager;
import com.x52im.rainbowchat.im.impl.ChatLogicManager4Group;
import com.x52im.rainbowchat.im.impl.MessageRecordManager;
import com.x52im.rainbowchat.im.impl.OfflineMessageManager;
import com.x52im.rainbowchat.im.impl.UsersStatusManager;
import com.x52im.rainbowchat.im.util.MessageHelper;

import com.x52im.rainbowchat.token.TokenManager;
import io.netty.channel.Channel;
import net.x52im.mobileimsdk.server.event.ServerEventListener;
import net.x52im.mobileimsdk.server.protocal.Protocal;

/**
 * IM Server 服务器业务事件处理主实现类.
 * 
 * @author Jack Jiang(http://www.52im.net/space-uid-1.html)
 * @version 1.0
 */
public class ChatServerEventListener implements ServerEventListener
{
	private static ChatServerEventListener instance = null;
	
//	private final Gson g = new Gson();
	
	/** 在线用户管理器 */
	private UsersStatusManager liverUsersMgr = null;
//	/** 聊天服务逻辑管理器（除群聊天） */
//	private ChatLogicManager chatLogicMgr = null;
//	/** 聊天服务逻辑管理器（群聊专用） */
//	private ChatLogicManager4Group groupChatLogicMgr = null;
	
	public static ChatServerEventListener getInstance()
	{
		if(instance == null)
			instance = new ChatServerEventListener();
		return instance;
	}
	
	private ChatServerEventListener()
	{
		liverUsersMgr = new UsersStatusManager();
//		chatLogicMgr = new ChatLogicManager();
	}
	
	/**
	 * 用户的IM连接/登陆请求身份验证回调方法定义.
	 * <p>
	 * 服务端的应用层可在本方法中实现用户登陆验证。
	 * <br>
	 * 注意：本回调在一种特殊情况下——即用户实际未退出登陆但再次发起来登陆包时，本回调是不会被调用的！
	 * <p>
	 * 根据MobileIMSDK的算法实现，本方法中用户验证通过（即方法返回值=0时）后
	 * ，将立即调用回调方法 {@link #onUserLoginSucess(String, String, Channel)}。
	 * 否则会将验证结果（本方法返回值错误码通过客户端的 ChatBaseEvent.onLoginMessage(int dwUserId, int dwErrorCode)
	 * 方法进行回调）通知客户端）。
	 * 
	 * @param userId 传递过来的准一id，保证唯一就可以通信，可能是登陆用户名、也可能是任意不重复的id等，具体意义由业务层决定
	 * @param token 用于身份鉴别和合法性检查的token，它可能是登陆密码，也可能是通过前置单点登陆接口拿到的token等，具体意义由业务层决定
	 * @param extra 额外信息字符串。本字段目前为保留字段，供上层应用自行放置需要的内容
	 * @param session 此客户端连接对应的会话
	 * @return 0 表示登陆验证通过，否则可以返回用户自已定义的错误码，错误码值应为：>=1025的整数
	 */
	@Override
	public int onUserLoginVerify(String userId, String token, String extra, Channel session)
	{
		return TokenManager.verifySocketToken(token);
//		if (BaseConf.getInstance().getTOKEN_FOR_SOCKET_VERIFY_ENABLED()) {
//			if (TokenManager.getInstance().verify(token) == null) {
//				LoggerFactory.getLog().debug("[RBChat]<token校验> 当前已启用socket token校验机制【YES】，校验失败，本次socket登录/连接将被拒绝【NO】！");
//				return 1025;
//			} else {
//				LoggerFactory.getLog().debug("[RBChat]<token校验> 当前已启用socket token校验机制【YES】，客户端已顺利通过合法身份校验，socket登录/连接验证完成【YES】。");
//			}
//		} else {
//			LoggerFactory.getLog().debug("[RBChat]<token校验> 当前已启用socket token校验机制【NO】，无需校验socket登录/连接请求。");
//		}
//
//		return 0;

////	try {
////		// 证认成功
////		if(LogicProcessor.userAuthentication(userId, token)) {
////			userID.setInt(0, id);
////			id++;
////			LoggerFactory.getLog().debug("用户身份验证--用户名："+lpUserName+" 密码："+lpPassword+" 昵称："+lpNickName+"");
//				return 0;
//			}
////		return 200; // 认证失败，用户名或密码有误
////	} catch (Exception e) {
////		return 200;
////	}
	}

	/**
	 * 用户的IM连接/登陆请求验证成功后的回调方法定义（即：上线通知）.
	 * <p>
	 * 服务端的应用层通常可在本方法中实现用户上线通知等。
	 * <br>
	 * 注意：本回调在一种特殊情况下——即用户实际未退出登陆但再次发起来登陆包时，回调也是一定会被调用。
	 * 
	 * @param userId 传递过来的准一id，保证唯一就可以通信，可能是登陆用户名、也可能是任意不重复的id等，具体意义由业务层决定
	 * @param extra 额外信息字符串。本字段目前为保留字段，供上层应用自行放置需要的内容。为了丰富应用层处理的手段，在本回调中也把此字段传进来了
	 * @param session 成功登陆后建立的MINA会话
	 */
	@Override
	public void onUserLoginSucess(String userId, String extra, Channel session)
	{
		LoggerFactory.getLog().info("[RBChat]用户连接IM服务器成功--用户ID:" + userId + ",远程IP:" 
				+ session.remoteAddress().toString());
		ChatLogicManager.processUserLoginAction(userId, extra, session);
	}

	/**
	 * 用户退出IM连接的回调方法定义（即：下线通知）。
	 * <p>
	 * 服务端的应用层通常可在本方法中实现用户下线通知等。
	 *
     * @param session 此客户端连接对应的 netty “会话”
     * @param beKickoutCode 被踢原因编码，本参数当为-1时表示本次logout事件不是源自“被踢”，否则被踢原因编码请见 {@link net.x52im.mobileimsdk.server.protocal.s.PKickoutInfo}类中的常量定义
     * @param session 此客户端连接对应的MINA会话
	 */
	@Override
	public void onUserLogout(String userId, Channel session, int beKickoutCode)
	{
		LoggerFactory.getLog().info("[RBChat]用户断开/注销IM服务器连接--" + "用户ID:" + userId);
		ChatLogicManager.processUserLogoutAction(userId, session, beKickoutCode);
	}

	/**
	 * 收到客户端发送给“服务端”的数据回调通知（即：消息路径为“C2S”的消息）前的处理逻辑。
	 * <p>
	 * <b>本方法的默认实现</b>：<font color="green">当开发者不需要本方法进行额外逻辑处理时，请直接返回true即可！</font>
	 * <p>
	 * <b>本方法的典型用途</b>：开发者可在本方法中实现如：用户聊天内容的鉴黄、过滤、篡改等等，把内容审读权限交给开发者，就看怎么用了。
	 *
	 * @param p 消息/指令的完整协议包对象
	 * @param session 消息发送者的“会话”引用（也就是客户端的网络连接对象）
	 * @return true表示经过本方法后将正常进入 {@link #onTransferMessage4C2S(Protocal, Channel)}继续正常逻辑  ，false表示该条指令将不会继续处理（直接被丢弃）
	 * @see #onTransferMessage4C2S(Protocal, Channel)
	 * @since 8.1
	 */
	@Override
	public boolean onTransferMessage4C2CBefore(Protocal p, Channel session)
	{
		return true;
	}

	/**
	 * 收到客户端发送给“其它客户端”的数据回调通知（即：消息路径为“C2C”的消息）前的处理逻辑。
	 * <p>
	 * <b>本方法的默认实现</b>：<font color="green">当开发者不需要本方法进行额外逻辑处理时，请直接返回true即可！</font>
	 * <p>
	 * <b>本方法的典型用途</b>：开发者可在本方法中实现如：用户聊天内容的鉴黄、过滤、篡改等等，把内容审读权限交给开发者，就看怎么用了。
	 *
	 * @param p 消息/指令的完整协议包对象
	 * @param session 消息发送者的“会话”引用（也就是客户端的网络连接对象）
	 * @return true表示经过本方法后将正常进入 {@link #onTransferMessage4C2C(Protocal)}继续正常逻辑  ，false表示该条指令将不会继续处理（直接被丢弃）
	 * @see #onTransferMessage4C2C(Protocal)
	 * @since 8.1
	 */
	@Override
	public boolean onTransferMessage4C2SBefore(Protocal p, Channel session)
	{
		return true;
	}

	/**
	 * 通用数据回调方法定义（客户端发给服务端的（即接收user_id="0"））.
	 * <p>
	 * MobileIMSDK在收到客户端向user_id=0(即接收目标是服务器)的情况下通过
	 * 本方法的回调通知上层。上层通常可在本方法中实现如：添加好友请求等业务实现。
	 * 
	 * @param p
	 * @param session 此客户端连接对应的MINA会话
	 * @return true表示本方法已成功处理完成，否则表示未处理成功。此返回值目前框架中并没有特殊意义，仅作保留吧
	 */
	@Override
	public boolean onTransferMessage4C2S(Protocal p, Channel session)
	{
		// 接收者uid
		String userId = p.getTo();
		// 发送者uid
		String from_user_id = p.getFrom();
		// 消息或指令内容
		String dataContent = p.getDataContent();
		// 消息或指令指纹码（即唯一ID）
		String fingerPrint = p.getFp();
		// 【重要】用户定义的消息或指令协议类型（开发者可据此类型来区分具体的消息或指令）
		int typeu = p.getTypeu();
		
		LoggerFactory.getLog().debug("[RBChat]收到了客户端"+from_user_id+"的C2S消息：str="+dataContent);
		
		// 客户端向userId=0的用户发送消息，即意味着向服务端发送消息,
		// 其实OnTransBuffer_CallBack方法当且仅当客户端向userId=0的用户发送消息时被触发.
		if("0".equals(userId))
		{
			try
			{
				final String msg = dataContent;
				LoggerFactory.getLog().debug("[RBChat]此消息接收对象为\"0\"(即server自已)。");
				// 处理用户A需要由服务端转发的临时聊天消息（给接收方B）
				if(typeu == UserProtocalsType.MT42_OF_TEMP$CHAT$MSG_A$TO$SERVER)
				{ 
					return ChatLogicManager.processMT42_OF_TEMP$CHAT$MSG_A$TO$SERVER(fingerPrint, msg);
				}
				// 处理用户A需要由服务端转发的群聊消息
				// @since RBChat2.4(2014-03-03)
				else if(typeu == UserProtocalsType.MT44_OF_GROUP$CHAT$MSG_A$TO$SERVER)
				{ 
					ChatLogicManager4Group.processMT44_OF_GROUP$CHAT$MSG_A$TO$SERVER(fingerPrint, msg);
				}
				// 处理用户A发起的添加好友请求
				else if(typeu == UserProtocalsType.MT05_OF_ADD_FRIEND_REQUEST_A$TO$SERVER)
				{
					// 解析添加好友请求原数据（客户端A发过来的）
					CMDBody4AddFriendRequest addFriendMetaFromClient = MessageHelper.pareseAddFriendRequestMessage(dataContent);
					// 进入处理逻辑并返回结果
					return ChatLogicManager.processMT05_OF_ADD_FRIEND_REQUEST_A$TO$SERVER(addFriendMetaFromClient);
				}
				// 被添加者【同意】加好友请求的消息（由B发给服务端） 
				else if(typeu == UserProtocalsType.MT08_OF_PROCESS_ADD$FRIEND$REQ_B$TO$SERVER_AGREE)
				{
					// 解析被添加者同意加好友请求原数据（客户端A发过来的）
					CMDBody4ProcessFriendRequest processFriendMetaFromClient = 
							MessageHelper.pareseProcessAdd$Friend$Req_B$To$Server_AGREEMessage(dataContent);
					// 进入处理逻辑并返回结果
					return ChatLogicManager.processMT08_OF_PROCESS_ADD$FRIEND$REQ_B$TO$SERVER_AGREE(processFriendMetaFromClient);
				}
				// 被添加者【拒绝】加好友请求的消息（由B发给服务端） 
				else if(typeu == UserProtocalsType.MT09_OF_PROCESS_ADD$FRIEND$REQ_B$TO$SERVER_REJECT)
				{
					// 解析被添加者拒绝加好友请求原数据（客户端A发过来的）
					CMDBody4ProcessFriendRequest processFriendMetaFromClient = 
							MessageHelper.pareseProcessAdd$Friend$Req_B$To$Server_REJECTMessage(dataContent);
					// 进入处理逻辑并返回结果
					ChatLogicManager.processMT09_OF_PROCESS_ADD$FRIEND$REQ_B$TO$SERVER_REJECT(processFriendMetaFromClient);
				}
			}
			catch (Exception e)
			{
				LoggerFactory.getLog().warn(e.getMessage(), e);
			}
			
			//
			return true;
		}
		
		//
		return false;
	}
	
	/**
	 * 通道数据回调函数定义（客户端发给客户端的（即接收方user_id不为“0”的情况））.
	 * <p>
	 * <b>注意：</b>本方法当且仅当在数据被服务端成功在线发送出去后被回调调用.
	 * <p>
	 * 上层通常可在本方法中实现用户聊天信息的收集，以便后期监控分析用户的行为等^_^。
	 * <p>
	 * 提示：如果开启消息QoS保证，因重传机制，本回调中的消息理论上有重复的可能，请以参数 #fingerPrint
	 * 作为消息的唯一标识ID进行去重处理。
	 * 
	 * @param p
	 */
	@Override
	public void onTransferMessage4C2C(Protocal p)
	{
		// 接收者uid
		String userId = p.getTo();
		// 发送者uid
		String from_user_id = p.getFrom();
		// 消息或指令内容
		String dataContent = p.getDataContent();
		// 消息或指令指纹码（即唯一ID）
		String fingerPrint = p.getFp();
		// 【重要】用户定义的消息或指令协议类型（开发者可据此类型来区分具体的消息或指令）
		int typeu = p.getTypeu();
				
//		logger.debug("收到了客户端"+from_user_id+"发给客户端"+userId+"的消息：str="+dataContent);
		
		// 【一对一好友聊天消息回调(可能来自桥接或本实例模式)】
		if(typeu == UserProtocalsType.MT03_OF_CHATTING_MESSAGE)
		{
			// ** 【用户消息收集】收集用户的聊天消息，以供后台进行用户行为分析，
			MessageRecordManager.colectChattingMsgAsync(dataContent, fingerPrint);
		}
		
		/******************************* 以下消息回调通知，只可能来自桥接模式 START *************************************/
		/** 因为根据MobileIMSDK APP端服务端器的设计逻辑，S2C消息本实例发送成功时，
		 *  由发送者在应用层处理自行决定余下逻辑（如存聊天记录），而不是由框架层的本回调处理 */
		// 【群聊消息回调(只可能来自桥接模式)】
		// 不要在此记录群聊消息（因为群聊消息应只记录发送的，而不记录接收的，
		// 否则1000个群员就得存1000条记录，而本回调就是接收的消息，所以不应在此存）。
		// 群聊消息的聊天记录，应在发送的时候存（谁发谁存，而不是谁收谁存，详见设计备忘录！）。
		else if(typeu == UserProtocalsType.MT45_OF_GROUP$CHAT$MSG_SERVER$TO$B)
		{// FIXME: 以下代码仅用于Debug时，并无实际业务逻辑，可以删除！
			
			// 什么也不用做
			LoggerFactory.getLog().debug("[RBChat]【Bridge2C_CallBack-群聊】[typeu=" + p.getTypeu() + "], 客户端" 
					+ p.getFrom() + " 发给客户端"+ p.getTo() + " 的实时消息：str=[" + dataContent
					+ "] 【根据S2C类型消息记录设计逻辑，此回调中无需存记录，忽略之！】");
		}
		// 【临时/陌生人聊天消息回调(只可能来自桥接模式)】
		// 陌生人消息不要在这里收集记录，根据目前的设计原则，s2c消息记录一律由发送者处理(而不是接收者)，详见设计备忘录
		else if(typeu == UserProtocalsType.MT43_OF_TEMP$CHAT$MSG_SERVER$TO$B)
		{// FIXME: 以下代码仅用于Debug时，并无实际业务逻辑，可以删除！
			
			// 什么也不用做
			LoggerFactory.getLog().debug("[RBChat]【Bridge2C_CallBack-陌生人聊】[typeu=" + p.getTypeu() + "], 客户端" 
					+ p.getFrom() + " 发给客户端"+ p.getTo() + " 的实时消息：str=[" + dataContent
					+ "] 【根据S2C类型消息记录设计逻辑，此回调中无需存记录，忽略之！】");
		}
		/******************************* 以下消息回调通知，只可能来自桥接模式 END *************************************/
		
		else
		{
			LoggerFactory.getLog().debug("[RBChat]【C2C_CallBack】[typeu=" + typeu + "], 客户端" + from_user_id + " 发给客户端"
					+ userId + " 的消息：str=[" + dataContent + "] 【不支持的typeu类型，无需进行聊天记录存储！！】");
		}
	}
	
	/**
	 * 服务端在进行消息发送时，当对方在线但实时发送失败、以及其它各种问题导致消息并没能正常发出时
	 * ，将无条件走本回调通知。
	 * <p>
	 * 注意：本方法当且仅当在数据被服务端<u>在线发送</u>失败后被回调调用.
	 * <p>
	 * <b>此方法存的意义何在？</b><br>
	 * 发生此种情况的场景可能是：对方确实不在线（那么此方法里就可以作为离线消息处理了）、
	 * 或者在发送时判断对方是在线的但服务端在发送时却没有成功（这种情况就可能是通信错误
	 * 或对方非正常通出但尚未到达会话超时时限）。<br><u>应用层在此方法里实现离线消息的处理即可！</u>
	 * 
	 * @param p
	 * @return true表示应用层已经处理了离线消息（如果该消息有QoS机制，则服务端将代为发送一条伪应答包
	 * （伪应答仅意味着不是接收方的实时应答，而只是存储到离线DB中，但在发送方看来也算是被对方收到，只是延
	 * 迟收到而已（离线消息嘛））），否则表示应用层没有处理（如果此消息有QoS机制，则发送方在QoS重传机制超时
	 * 后报出消息发送失败的提示）
	 */
	@Override
	public boolean onTransferMessage_RealTimeSendFaild(Protocal p)
	{
		return onTransferMessage_RealTimeSendFaild_impl(p, false);
	}
	
	/**
	 * onTransferMessage_RealTimeSendFaild的实现方法。
	 * 
	 * @param p 原始数据
	 * @param forceFriendChattingNoRecordHistory true表示强制不存储一对一好友聊天的聊天记录，否则存储
	 * @return true表示已妥善处理离线消息
	 */
	public boolean onTransferMessage_RealTimeSendFaild_impl(Protocal p, boolean forceFriendChattingNoRecordHistory)
	{
		// 接收者uid
		String userId = p.getTo();
		// 发送者uid
		String from_user_id = p.getFrom();
		// 消息或指令内容
		String dataContent = p.getDataContent();
		// 消息或指令指纹码（即唯一ID）
		String fingerPrint = p.getFp();
		// 【重要】用户定义的消息或指令协议类型（开发者可据此类型来区分具体的消息或指令）
		int typeu = p.getTypeu();
		
		// 此离线消息是否需要记录到聊天记录中
		boolean needRecordToChattingHistory = false;
		
		boolean processed = false;
		switch(typeu)
		{
			// 目前C2C的消息需要离线处理的，也就是用户的一对一好友聊天消息了
			case UserProtocalsType.MT03_OF_CHATTING_MESSAGE:
			{
//				processed = OfflineMessageManager.processOfflineMessage(p, false);
				
				// 强制不存储聊天记录（因为一对一好友聊天走的是c2c模式，它的聊天记录在QoS模
				// 式下已走 onTransferMessage4C2C()回调进行了存储，此参数就是为了在QoS场景下
				// 不需要重复存储聊天记录了）
				if(forceFriendChattingNoRecordHistory)
				{
					needRecordToChattingHistory = false;
				}
				else
				{
					/** 根据MobileIMSDK和Web端服务端器的设计逻辑，C2C好友聊天消息在接收方离线情况下的聊天记录处理，
					   * 需要在离线回调中处理（而不是在onTransBuffer_C2C_CallBack中），详见“RainbowChat_pro_v4关键设计思路备忘.txt” */
					needRecordToChattingHistory = true;
				}
//				
//				break;
			}
			
			/******************************* 以下离线处理，只可能来自桥接模式 START *************************************/
			/** 因为根据MobileIMSDK APP端服务端器的设计逻辑，S2C消息本实例发送失败时，由发送者在应用层处理，而不是由框架层的本回调处理 */
			//* 临时聊天消息的离线处理逻辑
			case UserProtocalsType.MT43_OF_TEMP$CHAT$MSG_SERVER$TO$B:
			//* 群组聊天消息的离线处理逻辑
			case UserProtocalsType.MT45_OF_GROUP$CHAT$MSG_SERVER$TO$B:
			//* 各群聊指令通知的离线处理逻辑
			case UserProtocalsType.MT46_OF_GROUP$SYSCMD_MYSELF$BE$INVITE_FROM$SERVER:	
			case UserProtocalsType.MT47_OF_GROUP$SYSCMD_COMMON$INFO_FROM$SERVER:	
			case UserProtocalsType.MT48_OF_GROUP$SYSCMD_DISMISSED_FROM$SERVER:
			case UserProtocalsType.MT49_OF_GROUP$SYSCMD_YOU$BE$KICKOUT_FROM$SERVER:
			case UserProtocalsType.MT50_OF_GROUP$SYSCMD_SOMEONEB$REMOVED_FROM$SERVER:
			case UserProtocalsType.MT51_OF_GROUP$SYSCMD_GROUP$NAME$CHANGED_FROM$SERVER:	
			{
				processed = OfflineMessageManager.processOfflineMessage(p, false);
				break;
			}
			/******************************* 以上离线处理，只可能来自桥接模式 END *************************************/
			
			default:
			{
				LoggerFactory.getLog().debug("[RBChat]【C2C】客户端"+from_user_id+"发给"+userId+"的消息类型typeu为"
						+typeu+"的消息或指令：str="+dataContent+"没有在离线处理逻辑内，本次离线回调被忽略哦！");
				processed = true;
				break;
			}
		}
		
		// 离线消息也要记录到聊天记录中
		if(needRecordToChattingHistory)
		{
			try
			{
				// ** 【用户消息收集并落库】收集用户的聊天消息，以供后台进行用户行为分析，
				MessageRecordManager.colectChattingMsgAsync(p.getDataContent(), p.getFp());
			}
			catch (Exception e)
			{
				LoggerFactory.getLog().warn(e.getMessage(), e);
			}
		}
		
		return processed;
	}

	/**
	 * <b>注意：</b><font color="red">本回调仅用于与Web的互通模式下，默认情况下本方法可什么也不做，无任何影响。如你对此回调有疑问可跟Jack Jiang进行技术讨论！</font>
	 * {@inheritDoc}
	 *
	 * @since 8.1
	 */
	@Override
	public void onTransferMessage4C2C_AfterBridge(Protocal p)
	{
		// 默认本方法可
	}

	public UsersStatusManager getLiverUsersMgr()
	{
		return liverUsersMgr;
	}
}
